package com.example.auth.filter;

import com.example.auth.service.CustomUserDetailsService;
import com.example.common.security.JwtUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT filter
 *
 * @author cui haida
 * @version JDK 8
 * 2025/8/4
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    /**
     * the utils of jwt
     */
    public JwtUtils jwtUtils;

    /**
     * the service of user detail
     * will get user info by username;
     */
    @Resource
    private CustomUserDetailsService customUserDetailsService;

    /**
     * filter handler
     *
     * @param request request
     * @param response response
     * @param filterChain the chain of filter
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            // get the token from the request
            String jwt = parseJwt(request);
            // validate the token
            if (jwt != null && jwtUtils.validateToken(jwt)) {
                // the username from token
                String username = jwtUtils.getUsernameFromToken(jwt);
                // get the whole user info by customUserDetailsService
                UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
                // create the auth
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                // set into authentication context
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                // set into security context
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            logger.error("Cannot set user authentication: {}", e);
        }

        filterChain.doFilter(request, response);
    }

    /**
     * get token from header
     *
     * @param request request
     * @return JWT string
     */
    private String parseJwt(HttpServletRequest request) {
        String headerAuth = request.getHeader("Authorization");

        if (headerAuth != null && headerAuth.startsWith("Bearer ")) {
            return headerAuth.substring(7);
        }

        return null;
    }
}